home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / Sample Code / Sample Editors⁄Viewers / Panel Editor / Source / Printer.cpp < prev    next >
Encoding:
Text File  |  1995-12-08  |  16.7 KB  |  642 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Printer.cpp
  3.  
  4.     Contains:    Implementation of CPrinter class for OpenDoc printing utility
  5.  
  6.     Written by:    Steve Smith, Thomas Weisbach, Jens Alfke
  7.  
  8.     Copyright:    © 1995 by Apple Computer, Inc., all rights reserved.
  9. */
  10.  
  11.  
  12.  
  13. // -- OpenDoc --
  14.  
  15. #ifndef _ALTPOINT_
  16. #include <AltPoint.h>
  17. #endif
  18.  
  19. #ifndef SOM_ODCanvas_xh
  20. #include <Canvas.xh>
  21. #endif
  22.  
  23. #ifndef SOM_ODClipboard_xh
  24. #include <Clipbd.xh>
  25. #endif
  26.  
  27. #ifndef SOM_Module_OpenDoc_Commands_defined
  28. #include <CmdDefs.xh>
  29. #endif
  30.  
  31. #ifndef SOM_ODDispatcher_xh
  32. #include <Disptch.xh>
  33. #endif
  34.  
  35. #ifndef SOM_ODFacet_xh
  36. #include <Facet.xh>
  37. #endif
  38.  
  39. #ifndef SOM_ODFrame_xh
  40. #include <Frame.xh>
  41. #endif
  42.  
  43. #ifndef SOM_ODMenuBar_xh
  44. #include <MenuBar.xh>
  45. #endif
  46.  
  47. #ifndef SOM_ODSession_xh
  48. #include <ODSessn.xh>
  49. #endif
  50.  
  51. #ifndef SOM_ODStorageSystem_xh
  52. #include <ODStor.xh>
  53. #endif
  54.  
  55. #ifndef SOM_ODPart_xh
  56. #include <Part.xh>
  57. #endif
  58.  
  59. #ifndef SOM_ODPlatformTypeList_xh
  60. #include <PfTypLs.xh>
  61. #endif
  62.  
  63. #ifndef SOM_ODShape_xh
  64. #include <Shape.xh>
  65. #endif
  66.  
  67. #ifndef SOM_Module_OpenDoc_StdProps_defined
  68. #include <StdProps.xh>
  69. #endif
  70.  
  71. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  72. #include <StdTypes.xh>
  73. #endif
  74.  
  75. #ifndef SOM_ODStorageUnit_xh
  76. #include <StorageU.xh>
  77. #endif
  78.  
  79. #ifndef SOM_ODTransform_xh
  80. #include <Trnsform.xh>
  81. #endif
  82.  
  83. #ifndef SOM_ODWindowState_xh
  84. #include <WinStat.xh>
  85. #endif
  86.  
  87. // -- OpenDoc Utilities --
  88.  
  89. #ifndef _EXCEPT_
  90. #include <Except.h>
  91. #endif
  92.  
  93. #ifndef _ITEXT_
  94. #include <IText.h>
  95. #endif
  96.  
  97. #ifndef _DLOGUTIL_
  98. #include <DlogUtil.h>
  99. #endif
  100.  
  101. #ifndef _ODDEBUG_
  102. #include <ODDebug.h>
  103. #endif
  104.  
  105. #ifndef _ODNEW_
  106. #include <ODNew.h>
  107. #endif
  108.  
  109. #ifndef _ODUTILS_
  110. #include <ODUtils.h>
  111. #endif
  112.  
  113. #ifndef _STORUTIL_
  114. #include <StorUtil.h>
  115. #endif
  116.  
  117. #ifndef _TEMPOBJ_
  118. #include <TempObj.h>
  119. #endif
  120.  
  121. #ifndef _USERSRCM_
  122. #include <UseRsrcM.h>
  123. #endif
  124.  
  125. // -- MacToolbox --
  126.  
  127. #ifndef __GESTALT__
  128. #include <Gestalt.h>
  129. #endif
  130.  
  131. #ifndef __GXGRAPHICS__
  132. #include <GXGraphics.h>
  133. #endif
  134.  
  135. #ifndef __GXPRINTING__
  136. #include <GXPrinting.h>
  137. #endif
  138.  
  139. #ifndef __PRINTING__
  140. #include <Printing.h>
  141. #endif
  142.  
  143. #ifndef __TEXTUTILS__
  144. #include <TextUtils.h>
  145. #endif
  146.  
  147. #ifndef __TOOLUTILS__
  148. #include <ToolUtils.h>
  149. #endif
  150.  
  151. // -- Printer --
  152. #define _PRINTER_PRIVATE_
  153. #ifndef _PRINTER_
  154. #include "Printer.h"
  155. #endif
  156.  
  157. #pragma segment Printer
  158.  
  159.  
  160. //=================================================================================
  161. // CWithPrintingOpen helper class
  162. //
  163. //    This is a stack-based object that opens printing in its constructor and
  164. //    closes it in its destructor. This provides a simple and exception-safe way
  165. //    to open up printing for the duration of a method or block.
  166. //=================================================================================
  167.  
  168. CWithPrintingOpen::CWithPrintingOpen( CPrinter *printer )
  169.     :fPrinter(kODNULL)
  170. {
  171.     if( ! printer->IsPrintingOpen() ) {
  172.         printer->OpenPrinting();            // Only open it if it wasn't open
  173.         fPrinter = printer;
  174.     }
  175. }
  176.  
  177. CWithPrintingOpen::~CWithPrintingOpen( )
  178. {
  179.     if( fPrinter )
  180.         fPrinter->ClosePrinting();            // Only close if printing was already open
  181. }
  182.  
  183.  
  184. //=================================================================================
  185. // CWithDialogState helper class
  186. //
  187. //    This is a stack-based object that sets up state for a modal dialog in its
  188. //    constructor, and resets the state in the destructor. It deactivates the front
  189. //    window, removes the "Redo" item from the Edit menu, and updates the Mac scrap.
  190. //=================================================================================
  191.  
  192. CWithDialogState::CWithDialogState( Environment *ev, ODSession *session )
  193. {
  194.     fEv = ev;
  195.     fWindowState = session->GetWindowState(ev);
  196.     TempODMenuBar menuBar = fWindowState->AcquireCurrentMenuBar(ev);
  197.     fWindowState->DeactivateFrontWindows(ev);
  198.     ODDialogBegin(ev, session, menuBar, kODNULL);
  199. }
  200.  
  201. CWithDialogState::~CWithDialogState( )
  202. {
  203.     ODDialogEnd();
  204.     fWindowState->ActivateFrontWindows(fEv);
  205. }
  206.  
  207.  
  208. //=================================================================================
  209. // BusyCursor helper function
  210. //=================================================================================
  211.  
  212. void BusyCursor( )
  213. {
  214.     SetCursor(*GetCursor(watchCursor));
  215. }
  216.  
  217. //=================================================================================
  218. // CPrinter implementation
  219. //=================================================================================
  220.  
  221. //---------------------------------------------------------------------------------
  222. // CPrinter::New  [static method]
  223. //---------------------------------------------------------------------------------
  224.  
  225. CPrinter* CPrinter::New( Environment *ev, ODStorageUnit *su )
  226. {
  227.     // Create & initialize the appropriate type of CPrinter object:
  228.     
  229.     long gxVersion, gxPrintVersion;
  230.     CPrinter *p;
  231.  
  232.     if ( Gestalt(gestaltGraphicsVersion, &gxVersion) == noErr &&
  233.             Gestalt(gestaltGXPrintingMgrVersion, &gxPrintVersion) == noErr &&
  234.             (void*)GXInitPrinting != (void*)kUnresolvedCFragSymbolAddress )
  235.         p= new CGXPrinter;
  236.     else
  237.         p= new CQDPrinter;
  238.         
  239.     TRY{
  240.         p->Initialize(ev,su);
  241.     }CATCH_ALL{
  242.         delete p;
  243.         RERAISE;
  244.     }ENDTRY
  245.     return p;
  246. }
  247.  
  248. //---------------------------------------------------------------------------------
  249. // CPrinter::CPrinter
  250. //---------------------------------------------------------------------------------
  251.  
  252. CPrinter::CPrinter()
  253. {
  254.     fDirty = kODFalse;
  255.     fPrintFacet = kODNULL;
  256.     fPrintingOpen = kODFalse;
  257. }
  258.  
  259. //---------------------------------------------------------------------------------
  260. // CPrinter::~CPrinter
  261. //---------------------------------------------------------------------------------
  262.  
  263. CPrinter::~CPrinter()
  264. {
  265.     WASSERTM(!fPrintingOpen,"Printing was not closed");
  266.     WASSERT(fPrintFacet==kODNULL);
  267.     ODSafeReleaseObject(fSU);
  268. }
  269.  
  270. //---------------------------------------------------------------------------------
  271. // CPrinter::Initialize
  272. //---------------------------------------------------------------------------------
  273.  
  274. void CPrinter::Initialize( Environment *ev, ODStorageUnit *su )
  275. {
  276.     ODAcquireObject(ev,su);
  277.     fSU = su;
  278.     fSession = ODGetSession(ev,su);
  279. }
  280.  
  281. //---------------------------------------------------------------------------------
  282. // CPrinter::OpenPrinting
  283. //---------------------------------------------------------------------------------
  284.  
  285. void CPrinter::OpenPrinting()
  286. {
  287.     WASSERTM(!fPrintingOpen,"OpenPrinting called twice");
  288.     fPrintingOpen = kODTrue;
  289. }
  290.  
  291. //---------------------------------------------------------------------------------
  292. // CPrinter::ClosePrinting
  293. //---------------------------------------------------------------------------------
  294.  
  295. void CPrinter::ClosePrinting()
  296. {
  297.     WASSERTM(fPrintingOpen,"ClosePrinting called twice");
  298.     fPrintingOpen = kODFalse;
  299. }
  300.  
  301. //---------------------------------------------------------------------------------
  302. // CPrinter::GetPlatformPrintJob
  303. //---------------------------------------------------------------------------------
  304.  
  305. ODPlatformPrintJob CPrinter::GetPlatformPrintJob( Environment* ev )
  306. {
  307.     // If the print job has not yet been loaded/created, do so now.
  308.     // Try to read a graphics-system-specific value from the standard page-setup property.
  309.     // The platform-specific subclass will do the dirty work of interpreting the
  310.     // data in the value, which we read into a handle for its convenience.
  311.     // If there is no stored page setup or it couldn't be read, make up a new one.
  312.     
  313.     ODPlatformPrintJob job = this->BasicGetPlatformPrintJob( );
  314.     
  315.     if( !job ) {
  316.         CWithPrintingOpen w(this);
  317.         
  318.         TRY
  319.             // Focus the storageUnit to the Print Job property.
  320.             if ( fSU->Exists(ev, kODPropPageSetup, kODNULL, 0) )
  321.             {
  322.                 ODValueType valueType = this->GetValueType();
  323.                 ODBoolean exists = fSU->Exists(ev,kODPropPageSetup,valueType,0);
  324.                 if( !exists ) {
  325.                     // Couldn't find main value type, try secondary one:
  326.                     valueType = this->GetSecondaryValueType();
  327.                     exists = valueType!=kODNULL && fSU->Exists(ev,kODPropPageSetup,valueType,0);
  328.                 }
  329.                 if( exists ) {
  330.                     // Found a value, now read it:
  331.                     fSU->Focus(ev, kODPropPageSetup, 0, valueType, 0, kODPosAll);
  332.                 
  333.                     ODULong size = fSU->GetSize(ev);
  334.                     TempODHandle data = ODNewHandle(size);
  335.                     StorageUnitGetValue(fSU,ev,size,ODLockHandle(data));
  336.                     ODUnlockHandle(data);
  337.                     job= this->ReadJobFromHandle(valueType,data.DontDelete());
  338.                 }
  339.             }
  340.         CATCH_ALL
  341.             WARN("Error %d internalizing print job",ErrorCode());
  342.         ENDTRY
  343.         
  344.         if( !job ) {
  345.             // Let's just make a new one:
  346.             job= this->CreateNewJob();
  347.             ASSERT(job!=kODNULL,kODErrAssertionFailed);
  348.         }
  349.     }
  350.     return job;
  351. }
  352.  
  353. //---------------------------------------------------------------------------------
  354. // CPrinter::Externalize
  355. //---------------------------------------------------------------------------------
  356.  
  357. void CPrinter::Externalize( Environment* ev, ODStorageUnit *su /*=kODNULL*/ )
  358. {
  359.     // su may be different from the part's storage unit (fSU) if the part
  360.     // is being cloned. NULL means use part's storage unit.
  361.     
  362.     if( su==kODNULL ) su=fSU;
  363.     
  364.     if( fDirty || su!=fSU ) {
  365.         CWithPrintingOpen w(this);
  366.         this->GetPlatformPrintJob(ev);
  367.         
  368.         TempODHandle data = this->CopyJobToHandle();
  369.         
  370.         // Focus to / create the Print Job property & value:
  371.         ODSUForceFocus(ev,su,kODPropPageSetup, this->GetValueType());
  372.         ODSize size = su->GetSize(ev);
  373.         if( size>0 )
  374.             su->DeleteValue(ev,size);
  375.         StorageUnitSetValue(su,ev,ODGetHandleSize(data),ODLockHandle(data));
  376.         
  377.         if( su==fSU )
  378.             fDirty = kODFalse;
  379.     }
  380. }
  381.  
  382. //---------------------------------------------------------------------------------
  383. // CPrinter::PageSetup
  384. //---------------------------------------------------------------------------------
  385.  
  386. ODBoolean CPrinter::PageSetup(Environment* ev)
  387. {
  388.     ODBoolean success = kODFalse;
  389.  
  390.     TRY
  391.         BusyCursor();
  392.         CWithPrintingOpen w(this);
  393.         CWithDialogState d(ev,fSession);
  394.         
  395.         this->GetPlatformPrintJob(ev);
  396.         
  397.         // Display the Page Setup dialog.
  398.         ODError err = kODNoError;
  399.         TRY{
  400.             InitCursor();
  401.             success = this->RunPageSetupDialog(ev);
  402.             if( success )
  403.                 fDirty = kODTrue;
  404.         }CATCH_ALL{
  405.             err = ErrorCode();
  406.         }ENDTRY
  407.         
  408.         THROW_IF_ERROR(err);
  409.  
  410.     CATCH_ALL
  411.         this->DisplayError(ev, ErrorCode());
  412.         success= kODFalse;
  413.     ENDTRY
  414.     InitCursor();
  415.     
  416.     return success;
  417. }
  418.  
  419. //---------------------------------------------------------------------------------
  420. // CPrinter::PrintDocument
  421. //---------------------------------------------------------------------------------
  422.  
  423. void CPrinter::PrintDocument(Environment* ev, ODFrame* initiator, ODShape* area /*=kODNULL*/)
  424. {
  425.     GrafPtr savePort;
  426.     GetPort(&savePort);
  427.     
  428.     BusyCursor();
  429.     
  430.     // If no area is specified, use the frameshape:
  431.     ODBoolean noAreaSupplied = (area==kODNULL);
  432.     if( noAreaSupplied )
  433.         area = initiator->AcquireFrameShape(ev,kODNULL);
  434.  
  435.     TRY
  436.         CWithDialogState d(ev,fSession);
  437.         
  438.         this->GetPlatformPrintJob(ev);
  439.         
  440.         CWithPrintingOpen w(this);
  441.     
  442.         ODError err = kODNoError;
  443.         TRY{
  444.             InitCursor();
  445.             if ( this->RunPrintDialog(ev) ) {
  446.                 BusyCursor();
  447.                 // Create OpenDoc printing geometry objects.
  448.                 this->SetupPrintingEnv(ev, initiator, area);
  449.             
  450.                 this->DoPrint(ev,area);
  451.             }
  452.         }CATCH_ALL{
  453.             err = ErrorCode();
  454.         }ENDTRY
  455.         
  456.         // Tear down printing objects. We do this here instead of right after DoPrint
  457.         // so that the cleanup will happen even if SetupPrintingEnv or DoPrint throw.
  458.         this->CleanupPrintingEnv(ev, initiator);
  459.  
  460.         THROW_IF_ERROR(err);        // Reraise the error, if any
  461.     
  462.     CATCH_ALL
  463.         // error occurred dialog
  464.         this->DisplayError(ev, ErrorCode());
  465.         if( noAreaSupplied )
  466.             ODReleaseObject(ev,area);
  467.     ENDTRY
  468.     
  469.     SetPort(savePort);
  470. }
  471.  
  472. //---------------------------------------------------------------------------------
  473. // CPrinter::SetupPrintingEnv
  474. //---------------------------------------------------------------------------------
  475.  
  476. void CPrinter::SetupPrintingEnv(Environment* ev, ODFrame* initiator, ODShape *area)
  477. {
  478.     if( fPrintFacet )
  479.         return;
  480.         
  481.     TempODPart part = initiator->AcquirePart(ev);
  482.  
  483.     // Create an external transform for our new facet
  484.     TempODTransform xtransform = initiator->CreateTransform(ev);
  485.     
  486.     // Create an OpenDoc shape equal to one page
  487.     ODRect cliprect = this->GetPageRect(ev);
  488.  
  489.     TempODShape clipshape = initiator->CreateShape(ev);
  490.     clipshape->SetRectangle(ev, &cliprect);
  491.  
  492.     // Get info about the type of canvas to create.
  493.     ODGraphicsSystem arch = this->GetGraphicsSystem();
  494.     ODPlatformCanvas port = this->CreatePrintingPlatformCanvas(ev,arch,initiator,area);
  495.  
  496.     // Get the window state to create objects. We need to do this
  497.     // because we don't have a valid facet yet.
  498.     ODWindowState* windowState = fSession->GetWindowState(ev);
  499.     
  500.     // Creating a printing canvas to add to our new facet.
  501.     ODCanvas* canvas = windowState->CreateCanvas(ev, arch, port, kODFalse, kODFalse);
  502.     TempODObject tempcanvas = canvas;        // Make sure it gets deleted on exception
  503.     if( arch != kODQuickDraw ) {
  504.         // Set up QD platform canvas if there isn't one already:
  505.         canvas->SetPlatformCanvas(ev, kODQuickDraw,
  506.                         this->CreatePrintingPlatformCanvas(ev,kODQuickDraw,initiator,area));
  507.     }
  508.     
  509.     canvas->SetOwner(ev, part);
  510.     canvas->SetPlatformPrintJob(ev, arch, this->GetPlatformPrintJob(ev));
  511.     
  512.     // Create a printing facet.
  513.     tempcanvas=kODNULL;
  514.     fPrintFacet = windowState->CreateFacet(ev, initiator, clipshape, xtransform,
  515.                                                 canvas, kODNULL);
  516.     
  517.     // Notify the intiator that a printing facet has been added to it.
  518.     TRY{
  519.         initiator->FacetAdded(ev, fPrintFacet);
  520.     }CATCH_ALL{
  521.         // ignore exceptions from part.
  522.     }ENDTRY
  523. }
  524.  
  525. //---------------------------------------------------------------------------------
  526. // CPrinter::CleanupPrintingEnv
  527. //---------------------------------------------------------------------------------
  528.  
  529. void CPrinter::CleanupPrintingEnv(Environment* ev, ODFrame* initiator)
  530. {
  531.     // Subclass should override to dispose platform canvas / platform print-job.
  532.     
  533.     if( fPrintFacet ) {
  534.         TRY{
  535.             initiator->FacetRemoved(ev, fPrintFacet);
  536.         }CATCH_ALL{
  537.         }ENDTRY
  538.         ODCanvas *canvas = fPrintFacet->GetCanvas(ev);
  539.         canvas->SetFacet(ev,kODNULL);
  540.         ODDeleteObject(fPrintFacet);
  541.         ODDeleteObject(canvas);
  542.     }
  543. }
  544.  
  545. //---------------------------------------------------------------------------------
  546. // CPrinter::CountPages
  547. //---------------------------------------------------------------------------------
  548.  
  549. ODULong CPrinter::CountPages(Environment* ev, ODShape* area)
  550. {
  551.     ODRect contentRect;
  552.     area->GetBoundingBox(ev, &contentRect);
  553.     
  554.     ODRect pageRect = this->GetPageRect(ev);
  555.     
  556.     ODULong horiPages = (contentRect.Width()+pageRect.Width()-1)   / pageRect.Width();
  557.     ODULong vertPages = (contentRect.Height()+pageRect.Height()-1) / pageRect.Height();
  558.     
  559.     ODULong pageCount = horiPages * vertPages;
  560.     if( pageCount == 0 )
  561.         pageCount = 1;
  562.     
  563.     return pageCount;
  564. }
  565.  
  566. //---------------------------------------------------------------------------------
  567. // CPrinter::SetPage
  568. //---------------------------------------------------------------------------------
  569.  
  570. void CPrinter::SetPage(Environment* ev, ODUShort pageNum, ODShape* area)
  571. {
  572.     ODRect contentRect;
  573.     area->GetBoundingBox(ev, &contentRect);
  574.     
  575.     ODRect pageRect = this->GetPageRect(ev);
  576.     
  577.     // Calc horizontal pages, don't let be less than one
  578.     ODUShort horiPages = (contentRect.Width()+pageRect.Width()-1) / pageRect.Width();
  579.     if (horiPages < 1)
  580.         horiPages = 1;
  581.     
  582.     // Create a transform which translates the clip shape (page region)
  583.     // back to a {0,0} coordinate space.
  584.     ODPoint offset;
  585.     offset.x = -( contentRect.left + ((pageNum - 1) % horiPages) * pageRect.Width() );
  586.     offset.y = -( contentRect.top  + ((pageNum - 1) / horiPages) * pageRect.Height() ); 
  587.     
  588.     TempODTransform transform = fPrintFacet->CreateTransform(ev);
  589.     transform->SetOffset(ev, &offset);
  590.     
  591.     // Set up a clip-shape to fit the transformed facet:
  592.     TempODShape clipShape = fPrintFacet->CreateShape(ev);
  593.     clipShape->SetRectangle(ev, &pageRect);
  594.     clipShape->InverseTransform(ev,transform);
  595.     clipShape->Intersect(ev,area);                    // Restrict to frameshape
  596.  
  597.     // Update the facet's geometry.
  598.     fPrintFacet->ChangeGeometry(ev, clipShape, transform, fPrintFacet->GetCanvas(ev));
  599. }
  600.  
  601. //---------------------------------------------------------------------------------
  602. // CPrinter::PrintPage
  603. //---------------------------------------------------------------------------------
  604.  
  605. void CPrinter::PrintPage(Environment* ev, ODUShort page, ODShape *area)
  606. {
  607.     // Main routine to print a particular page.
  608.     
  609.     this->SetPage(ev, page, area);
  610.     this->OpenPage(ev, page);
  611.     
  612.     TempODShape clip = fPrintFacet->AcquireClipShape(ev, kODNULL);
  613.     fPrintFacet->Update(ev, clip, kODNULL);
  614.     
  615.     this->ClosePage(ev);
  616. }
  617.  
  618. //---------------------------------------------------------------------------------
  619. // CPrinter::DisplayError
  620. //---------------------------------------------------------------------------------
  621.  
  622. void CPrinter::DisplayError(Environment* ev, ODSShort error)
  623. {
  624.     Str255        message;
  625.     Str15        number;
  626.     
  627.     CUsingLibraryResources r;
  628.     CWithDialogState d(ev,fSession);
  629.     
  630.     // Use the default (generic) error message unless we recognize the
  631.     // error number.
  632.     ODUShort index = 1;
  633. //    if ( error == -4101 ) index = 2;        // no printer selected.  $$$$$ This is not correct
  634.     if ( error == fnfErr ) index = 2;        // no printer selected.  ••• This is 
  635.     
  636.     GetIndString(message, rPrintErrorsID, index);
  637.     NumToString(error,number);
  638.     ParamText(message,number,kODNULL,kODNULL);
  639.  
  640.     ShowAlert(ev,rPrintErrorDialog,kODNULL,fSession);
  641. }
  642.